#ifndef __FIXEDVECTOR_H_INCLUDED__
#define __FIXEDVECTOR_H_INCLUDED__

#include <glf/fstl/fixed_base.h>

#include <iosfwd>

namespace glf {

template<typename T, size_t N, bool AllowOverflow=false, typename OverflowAllocator=std::allocator<T> > //game_allocator<T>
struct fixed_vector : public fixed_container<T, N> {
	typedef OverflowAllocator	allocator_type;

	typedef fixed_vector<T, N, AllowOverflow, OverflowAllocator>	MyType;

	//stupid template stuff
	typedef typename iterable<T>::iterator iterator;
	iterator end() {
		return fixed_container<T,N>::end();
	}
	T* ptr(size_t idx) {
		return fixed_container<T,N>::ptr(idx);
	}
	
	//constructors & destructor
	fixed_vector() :
		fixed_container<T,N>() {
	}
	explicit fixed_vector(size_t n) :
		fixed_container<T,N>() {
		construct_n(n, T());
	}
	fixed_vector(size_t n, const T& elem) :
		fixed_container<T,N>() {
		construct_n(n, elem);
	}	
	fixed_vector(size_t n, const T& elem, const allocator_type& al) :
		fixed_container<T,N>() {
		construct_n(n, elem);
	}
	explicit fixed_vector(const allocator_type& al) :
		fixed_container<T,N>() {
	}
	template <class InputIterator>
	fixed_vector(InputIterator first, InputIterator last) :
		fixed_container<T,N>() {

		for(InputIterator it = first; it != last; ++it) {
			push_back(*it);
		}
	}
	//template <class InputIterator>
	//fixed_vector(InputIterator first, InputIterator last, const allocator_type& al);
	template<size_t N2>
	fixed_vector(const fixed_vector<T, N2>& rhs) :
		fixed_container<T,N>(){

		for(iterator it = rhs.begin(); it != rhs.end(); ++it) {
			push_back(*it);
		}

	}
	~fixed_vector() {
		clear();
	}
	size_t size() const {
		return fixed_base_ctor<T>::size();
	}

	//capacity functions
	void resize(size_t n) {
		resize(n, T());
	}
	void resize(size_t n, T elem) {
		if(n < size()) {
			destruct_n(size(), size()-n);
		} else if(n <= N) {
			construct_n(n - size(), elem);
		} else if(AllowOverflow) {
			//grow
		} else {
			//throw, assert do nothing ??
		}
	}
	bool empty() const {
		return this->mSize == 0;
	}
	void reserve(size_t n) {
		GLF_ASSERT(n < N || (AllowOverflow && n < this->capacity()));

		if(AllowOverflow && n > N) {
			//grow
		}
	}
	//Element access
	T& at(size_t idx) {
		GLF_ASSERT(idx < size());
		return *(reinterpret_cast<T*>(this->mBuffer) + idx);
	}
	const T& at(size_t idx) const {
		GLF_ASSERT(idx < size());
		return *(reinterpret_cast<const T*>(this->mBuffer) + idx);
	}
	T& operator[](size_t n) {
		return at(n);
	}
	const T& operator[](size_t n) const {
		return at(n);
	}
	T& back() {
		GLF_ASSERT(!empty());
		return at(size()-1);
	}
	const T& back() const {
		GLF_ASSERT(!empty());
		return at(0);
	}
	T& front() {
		GLF_ASSERT(!empty());
		return at(0);
	}
	const T& front() const {
		GLF_ASSERT(!empty());
		return at(0);
	}
	//modifiers:
	void push_back(const T& elem) {
		construct_n(1, elem);
	}
	T& push_one() {
		push_back(T());
		return back();
	}
	void pop_back() {
		GLF_ASSERT(!empty());
		resize(size() - 1);
	}
	//template <class InputIterator>
	//void assign ( InputIterator first, InputIterator last );
	void assign(size_t n, const T& u) {
		resize(0);
		construct_n(n, u);
	}

	//iterator insert ( iterator position, const T& x );
	//void insert ( iterator position, size_type n, const T& x );
	//template <class InputIterator>
	//void insert ( iterator position, InputIterator first, InputIterator last );
	iterator erase(iterator position ) {
		if(position != end()) {
			copy(position + 1, end(), position);
			(end() - 1)->~T();
			--this->mSize;
		}
		return position;
	}
	iterator erase(iterator first, iterator last) {
		while(first != last) {
			first->~T();
			++first;
			--this->mSize;
		}
		return first;
	}
	template<size_t N2>
	void swap(fixed_vector<T,N2>& rhs) {
		//ASSERT(rhs.size() < vec.capacity());
		//ASSERT(size() < capacity());
	}
	void clear() { 
		resize(0);
	}
private:
	fixed_vector(const MyType& right);
	MyType& operator=(const MyType& right);


	void construct_n(size_t n, const T& val) {
		size_t startIdx = size();
		for(size_t i = 0; i < n; ++i) {
			new (ptr(startIdx+i)) T(val);
		}
		this->mSize += n;
	}
	
	void destruct_n(size_t startIdx, size_t num) {
		for(size_t i = 0; i < num; ++i) {
			at(startIdx-1-i).~T();
		}
		this->mSize -= num;
	}

	void copy(iterator begin, iterator end, iterator destination) {
		while(begin != end) {
			*destination++ = *begin++;
		}
	}

	//size_t mSize;
	//char mBuffer[sizeof(T) * N];

//#if GLF_CONFIG_DEBUG
	//T (*mDbgElems)[N];
	size_t mDbgWaterMark;
//#endif
};

}

#endif
